home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*
- * path -
- * General functions to support creation of PostScript
- * stroked, filled, and beveled paths.
- *
- * Paul Haeberli - 1990
- */
- #include "stdio.h"
- #include "gl.h"
- #include "sgiobj.h"
- #include "vect.h"
- #include "path.h"
-
- /* #define MAKETMESHES */
- /*
- * function prototypes
- *
- *
- */
- extern sgiobj *getfaces();
- extern sgiobj *follow();
-
- static void checkpath();
- static void addtopath(path *p, pathseg *ps);
- static addline(path *p, float x1, float y1, float x2, float y2);
- static addcurve(path *p, float x1, float y1, float x2, float y2,
- float x3, float y3, float x4, float y4);
- static int nfloats(path *p);
- static void flattenpath(path *p);
- static bezadapt(float x0,float y0,float x1,float y1,
- float x2,float y2,float x3,float y3,float beztol,path *p, int startb);
- static void entershape(path *p, int dopath);
-
- /*
- * global variables
- *
- *
- */
- static float curflatness = -1.0;
- static float curx, cury;
- static float startx, starty;
- static path *curpath;
- static path *bevpath;
- static int nsegs;
-
- /*
- * internal functions
- *
- *
- */
- static void checkpath()
- {
- if(!curpath) {
- curpath = (path *)mymalloc(sizeof(path));
- curpath->type = TYPE_BUILD;
- curpath->ncurves = 0;
- curpath->head=0;
- curpath->tail=0;
- curpath->data=0;
- nsegs = 0;
- }
- }
-
- static void addtopath(path *p, pathseg *ps)
- {
- ps->next = 0;
- if(p->tail) {
- p->tail->next = ps;
- p->tail = ps;
- } else
- p->head = p->tail = ps;
- }
-
- static addline(path *p, float x1, float y1, float x2, float y2)
- {
- pathline *pl;
-
- pl = (pathline *)mymalloc(sizeof(pathline));
- pl->x1 = x1;
- pl->x2 = x2;
- pl->y1 = y1;
- pl->y2 = y2;
- pl->dx1 = x2-x1;
- pl->dy1 = y2-y1;
- pl->dx2 = x2-x1;
- pl->dy2 = y2-y1;
- if(nsegs == 0)
- pl->attr = SEG_LINE|START_BIT;
- else
- pl->attr = SEG_LINE;
- addtopath(curpath,(pathseg *)pl);
- nsegs++;
- }
-
- static addcurve(path *p, float x1, float y1, float x2, float y2,
- float x3, float y3, float x4, float y4)
- {
- pathcurve *pc;
-
- curpath->ncurves++;
- pc = (pathcurve *)mymalloc(sizeof(pathcurve));
- pc->x1 = x1;
- pc->x2 = x2;
- pc->x3 = x3;
- pc->x4 = x4;
- pc->y1 = y1;
- pc->y2 = y2;
- pc->y3 = y3;
- pc->y4 = y4;
- if(nsegs == 0)
- pc->attr = SEG_CURVE|START_BIT;
- else
- pc->attr = SEG_CURVE;
- addtopath(curpath,(pathseg *)pc);
- nsegs++;
- }
-
- static int nfloats(path *p)
- {
- int nf;
- pathseg *ps;
- path *flatp, fp;
-
- nf = 0;
- ps = curpath->head;
- while(ps) {
- nf += 2;
- if(ps->attr & START_BIT) {
- nf++;
- nf += 2;
- }
- ps = ps->next;
- }
- nf++;
- return nf;
- }
-
- static void flattenpath(path *p)
- {
- pathseg *ps, *txen, *pstart;
- pathcurve *pc;
- int startb;
-
- if(curpath->ncurves == 0)
- return;
- if(curflatness<0.0) {
- fprintf(stderr,"must call setflat(flatness) before using curves\n");
- exit(1);
- }
- pstart = p->head;
- p->head = p->tail = 0;
-
- ps = pstart;
- while(ps) {
- txen = ps->next;
- ps = txen;
- }
- ps = pstart;
- while(ps) {
- txen = ps->next;
-
- if((ps->attr&SEG_MASK) == SEG_LINE) {
- addtopath(p,ps);
- } else {
- startb = ps->attr & START_BIT;
- pc = (pathcurve *)ps;
- bezadapt(pc->x1,pc->y1,pc->x2,pc->y2,
- pc->x3,pc->y3,pc->x4,pc->y4,curflatness,p,startb);
- free(ps);
- }
- ps = txen;
- }
- p->ncurves = 0;
- }
-
- static bezadapt(float x0,float y0,float x1,float y1,
- float x2,float y2,float x3,float y3,float beztol,path *p, int startb)
- {
- float ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3;
- float bx0,by0,bx1,by1,bx2,by2,bx3,by3;
- float midx, midy;
- float linx, liny, dx, dy, mag;
- pathline *pl;
-
- midx = (x0+3*x1+3*x2+x3)/8.0;
- midy = (y0+3*y1+3*y2+y3)/8.0;
- linx = (x0+x3)/2.0;
- liny = (y0+y3)/2.0;
- dx = midx-linx;
- dy = midy-liny;
- mag = dx*dx+dy*dy;
- if(mag<(beztol*beztol)) {
- /* drawline(x0,y0,x3,y3,x1-x0,y1-y0,x3-x2,y3-y2); */
- pl = (pathline *)mymalloc(sizeof(pathline));
- pl->x1 = x0;
- pl->y1 = y0;
- pl->x2 = x3;
- pl->y2 = y3;
- pl->dx1 = x1-x0;
- pl->dy1 = y1-y0;
- pl->dx2 = x3-x2;
- pl->dy2 = y3-y2;
- if(startb) {
- pl->attr = SEG_LINE|START_BIT;
- } else
- pl->attr = SEG_LINE;
- addtopath(p,(pathseg *)pl);
- } else {
- ax0 = x0;
- ay0 = y0;
- ax1 = (x0+x1)/2.0;
- ay1 = (y0+y1)/2.0;
- ax2 = (x0+2.0*x1+x2)/4.0;
- ay2 = (y0+2.0*y1+y2)/4.0;
- ax3 = midx;
- ay3 = midy;
- bezadapt(ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3,beztol,p,startb);
-
- bx0 = midx;
- by0 = midy;
- bx1 = (x1+2.0*x2+x3)/4.0;
- by1 = (y1+2.0*y2+y3)/4.0;
- bx2 = (x2+x3)/2.0;
- by2 = (y2+y3)/2.0;
- bx3 = x3;
- by3 = y3;
- bezadapt(bx0,by0,bx1,by1,bx2,by2,bx3,by3,beztol,p,0);
- }
- }
-
- static void entershape(path *p, int dopath)
- {
- vect s, l, c;
- vect ds, dl, dc;
- int nsides;
- pathline *pl;
-
- pl = (pathline *)p->head;
- if(dopath)
- pathbegin();
- else
- tempbegin();
- nsides = 0;
- while(pl) {
- if(pl->attr & START_BIT) {
- if(nsides>0 && dopath) {
- if(c.x != s.x || c.y != s.y)
- mypathsegment(&c,&dc,&s,&ds);
- pathclose();
- }
- nsides = 0;
- }
- l.x = pl->x1;
- l.y = pl->y1;
- dl.x = pl->dx1;
- dl.y = pl->dy1;
- c.x = pl->x2;
- c.y = pl->y2;
- dc.x = pl->dx2;
- dc.y = pl->dy2;
- if(nsides == 0) {
- s = l;
- ds = dl;
- }
- if(dopath)
- mypathsegment(&l,&dl,&c,&dc);
- else
- tempsegment(&l,&dl,&c,&dc);
- nsides++;
- pl = (pathline *)pl->next;
- }
- if(nsides>0 && dopath) {
- if(c.x != s.x || c.y != s.y)
- mypathsegment(&c,&dc,&s,&ds);
-
- }
- if(dopath)
- pathclose();
- else
- tempclose();
- }
-
- mypathsegment(v1,dv1,v2,dv2)
- vect *v1,*dv1,*v2,*dv2;
- {
- pathsegment(v1,dv1,v2,dv2);
- }
-
- /*
- * set global properties
- *
- *
- */
- void setflat(float flat)
- {
- curflatness = flat;
- }
-
- void setbevel()
- {
- checkpath();
- freepath(bevpath);
- flattenpath(curpath);
- bevpath = curpath;
- curpath = 0;
- }
-
- /*
- * build a path structure
- *
- *
- */
- void newpath()
- {
- checkpath();
- }
-
- void closepath()
- {
- if(curpath && curpath->tail)
- lineto(startx,starty);
- nsegs = 0;
- }
-
- void moveto(float x, float y)
- {
- startx = curx = x;
- starty = cury = y;
- nsegs = 0;
- }
-
- void lineto(float x, float y)
- {
- checkpath();
- if(x != curx || y != cury) {
- addline(curpath,curx,cury,x,y);
- curx = x;
- cury = y;
- }
- }
-
- void curveto(float x1, float y1, float x2, float y2, float x3, float y3)
- {
- checkpath();
- addcurve(curpath,curx,cury,x1,y1,x2,y2,x3,y3);
- curx = x3;
- cury = y3;
- }
-
- /*
- * free a path
- *
- */
- void freepath(path *p)
- {
- pathseg *ps, *next;;
-
- if(!p)
- return;
- switch(p->type) {
- case TYPE_BUILD:
- ps = p->head;
- while(ps) {
- next = ps->next;
- free(ps);
- ps = next;
- }
- free(p);
- break;
- case TYPE_STROKE:
- free(p->data);
- free(p);
- break;
- case TYPE_FILL:
- case TYPE_BEVELED:
- freesgiobj(p->data);
- free(p);
- break;
- }
- }
-
- /*
- * create a path using current bevel and current flatness.
- *
- *
- */
- path *stroke()
- {
- pathline *pl;
- path *p;
- int nf, count;
- float *fptr, *cptr;
-
- checkpath();
- flattenpath(curpath);
- nf = nfloats(curpath);
- p = (path *)mymalloc(sizeof(path));
- p->type = TYPE_STROKE;
- p->data=(char *)mymalloc(nf*sizeof(float));
- fptr = (float*)p->data;
- pl = (pathline *)curpath->head;
- cptr = 0;
- count = 0;
- while(pl) {
- nf += 2;
- if(pl->attr & START_BIT) {
- if(cptr) {
- *cptr = count;
- count = 0;
- }
- cptr = fptr;
- fptr++;
- *fptr++ = pl->x1;
- *fptr++ = pl->y1;
- count++;
- }
- *fptr++ = pl->x2;
- *fptr++ = pl->y2;
- count++;
- pl = (pathline *)pl->next;
- }
- if(cptr)
- *cptr = count;
- *fptr++ = 0;
- freepath(curpath);
- curpath = 0;
- return p;
- }
-
- path *fill()
- {
- float x, y;
- vect p0, p1, s, l, c;
- int nsides;
- pathline *pl;
- path *p;
- sgiobj *obj, *tobj;
-
- checkpath();
- flattenpath(curpath);
-
- tempbegin();
- p0.x = 1.0;
- p0.y = 0.0;
- p1.x = 0.0;
- p1.y = 0.0;
- tempsegment(&p0,0,&p1,0);
-
- entershape(curpath,1);
- obj = getfaces();
-
- p = (path *)mymalloc(sizeof(path));
- p->type = TYPE_FILL;
- p->data=(char *)obj;
- freepath(curpath);
- curpath = 0;
- return p;
- }
-
- path *bevel3d()
- {
- vect p0, p1;
- pathline *pl;
- path *p;
- sgiobj *obj, *fobj, *bobj, *tobj;
-
- checkpath();
- flattenpath(curpath);
-
- if(bevpath) {
- entershape(bevpath,0);
-
- entershape(curpath,1);
-
- fobj = getfaces();
- bobj = follow();
- if(fobj && bobj) {
- obj = catsgiobj(fobj,bobj);
- freesgiobj(fobj);
- freesgiobj(bobj);
- } else if(fobj)
- obj = fobj;
- else if(bobj)
- obj = bobj;
- else {
- printf("no objects from getfaces and follow\n");
- exit(1);
- }
-
- p = (path *)mymalloc(sizeof(path));
- p->type = TYPE_BEVELED;
- p->data=(char *)obj;
- }
- freepath(curpath);
- curpath = 0;
- return p;
- }
-
- /*
- * actually draw a path
- *
- *
- */
- void drawpath(path *p)
- {
- float *fptr;
- int n;
-
- switch(p->type) {
- case TYPE_STROKE:
- fptr = (float *)p->data;
- n = *fptr++;
- while(n>0) {
- bgnline();
- while(n--) {
- v2f(fptr);
- fptr += 2;
- }
- endline();
- n = *fptr++;
- }
- break;
- case TYPE_FILL:
- drawsgiobj(p->data,DRAW_POINTS);
- break;
- case TYPE_BEVELED:
- drawsgiobj(p->data,DRAW_POINTS|DRAW_NORMALS);
- break;
-
- }
- }
-
-